package top.iszsq.config.advice;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.method.HandlerMethod;
import top.iszsq.base.entity.Result;
import top.iszsq.base.exceptions.BizException;
import top.iszsq.base.utils.RenderUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.List;

/**
 * 全局异常处理
 * @author zsq
 * @date 2021/5/18 15:25
 **/
@ControllerAdvice
public class GlobalExceptionHandler {

    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 处理 自定义业务异常
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value = BizException.class)
    @ResponseBody
    public Result exceptionHandler(HttpServletRequest req, BizException e, HandlerMethod handlerMethod){
        logger.error("发生 自定义业务异常！e:", e);

        // 得到异常棧的首个元素
        StackTraceElement trace = e.getStackTrace()[0];
        String logInfo = String.format("自定义业务异常，原因：%s，出错类：%s，出错方法：%s，出错行号：%s",
                e.getMessage(),
                trace.getFileName(),
                trace.getMethodName(),
                trace.getLineNumber());
        logger.error(logInfo);

        return e.getRender();
    }

    /**
     * 处理空指针的异常
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value = NullPointerException.class)
    @ResponseBody
    public Result exceptionHandler(HttpServletRequest req, NullPointerException e){
        logger.error("发生空指针异常！原因:", e);

        logger.error("请求地址:" + req.getRequestURI());

        Throwable cause = e.getCause();
        String message = e.getMessage();
        if (cause != null) {
            message = cause.getMessage();
        }

        // 得到异常棧的首个元素
        StackTraceElement trace = e.getStackTrace()[0];
        String logInfo = String.format("空指针的异常，原因：%s，出错类：%s，出错方法：%s，出错行号：%s",
                message,
                trace.getFileName(),
                trace.getMethodName(),
                trace.getLineNumber());
        logger.error(logInfo);

        return RenderUtils.fail("系统异常");
    }

    /**
     * 处理全局系统异常
     * @param req
     * @param e
     * @param handlerMethod 处理方法
     * @return
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public Result exceptionHandler(HttpServletRequest req, Exception e, HandlerMethod handlerMethod){
        logger.error("-------系统异常！e:", e);

        logger.error("-------系统异常！handlerMethod:" + handlerMethod);
        logger.error("-------请求地址:" + req.getRequestURI());

        // 得到异常棧的首个元素
        StackTraceElement trace = e.getStackTrace()[0];
        String logInfo = String.format("系统异常，原因：%s，出错类：%s，出错方法：%s，出错行号：%s",
                e.getMessage(),
                trace.getFileName(),
                trace.getMethodName(),
                trace.getLineNumber());
        logger.error(logInfo);

        return RenderUtils.fail("系统异常");
    }

    /**
     * 参数校验异常
     * @param ex
     * @return
     */
    @ExceptionHandler(value = BindException.class)
    @ResponseBody
    public Result bindExceptionHandler(BindException ex){
        logger.debug("参数校验异常：", ex);
        List<FieldError> fieldErrorList = ex.getFieldErrors();
        String message = "参数校验异常";
        String fieldName = "";
        if (fieldErrorList != null && !fieldErrorList.isEmpty()) {
            message = fieldErrorList.get(0).getDefaultMessage();
            fieldName = fieldErrorList.get(0).getField();
        }

        return RenderUtils.fail(message).setData(fieldName);
    }

    /**
     * 参数校验异常
     * @param ex
     * @return
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    @ResponseBody
    public Result bindExceptionHandler(MethodArgumentNotValidException ex){
        logger.debug("参数校验异常：", ex);
        List<FieldError> fieldErrorList = ex.getBindingResult().getFieldErrors();
        String message = "参数校验异常";
        String fieldName = "";
        if (fieldErrorList != null && !fieldErrorList.isEmpty()) {
            message = fieldErrorList.get(0).getDefaultMessage();
            fieldName = fieldErrorList.get(0).getField();
        }

        return RenderUtils.fail(message).setData(fieldName);
    }

}
